package com.xiang.ad.index.creativeunit;

import com.xiang.ad.index.IndexAware;
import com.xiang.ad.index.adunit.AdUnitObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;

/**
 * Created by xiang.
 * 创意&推广单元 关联 index服务
 */
@Slf4j
@Component
public class CreativeUnitIndex implements
        IndexAware<String, CreativeUnitObject> {

    // <adId-unitId, CreativeUnitObject>
    private static Map<String, CreativeUnitObject> objectMap;//
    // <adId, unitId Set>
    private static Map<Long, Set<Long>> creativeUnitMap;//
    // <unitId, adId set>  推广单元的id 对应到多个创意的id，这个用于通过推广单元获取关联的创意
    private static Map<Long, Set<Long>> unitCreativeMap;//

    //使用线程安全的ConcurrentHashMap初始化三个map
    static {
        objectMap = new ConcurrentHashMap<>();
        creativeUnitMap = new ConcurrentHashMap<>();
        unitCreativeMap = new ConcurrentHashMap<>();
    }

    //通过adId-unitId 获取 CreativeUnitObject
    @Override
    public CreativeUnitObject get(String key) {
        return objectMap.get(key);
    }

    //添加（更新）索引
    @Override
    public void add(String key, CreativeUnitObject value) {

        log.info("before add: {}", objectMap);

        //添加（更新）objectMap
        objectMap.put(key, value);

        //添加（更新）creativeUnitMap
        Set<Long> unitSet = creativeUnitMap.get(value.getAdId());
        if (CollectionUtils.isEmpty(unitSet)) {//为空就new 然后put进去
            unitSet = new ConcurrentSkipListSet<>();
            creativeUnitMap.put(value.getAdId(), unitSet);
        }
        unitSet.add(value.getUnitId());

        //添加（更新）unitCreativeMap
        Set<Long> creativeSet = unitCreativeMap.get(value.getUnitId());
        if (CollectionUtils.isEmpty(creativeSet)) {
            creativeSet = new ConcurrentSkipListSet<>();
            unitCreativeMap.put(value.getUnitId(), creativeSet);
        }
        creativeSet.add(value.getAdId());

        log.info("after add: {}", objectMap);
    }

    //更新索引，更新成本高，不提供更新方法
    @Override
    public void update(String key, CreativeUnitObject value) {

        log.error("CreativeUnitIndex not support update");
    }

    //删除索引
    @Override
    public void delete(String key, CreativeUnitObject value) {

        log.info("before delete: {}", objectMap);

        //根据key，直接删除objectMap
        objectMap.remove(key);

        //删除creativeUnitMap
        Set<Long> unitSet = creativeUnitMap.get(value.getAdId());//根据广告的id获取与之关联的unitId的set
        if (CollectionUtils.isNotEmpty(unitSet)) {
            unitSet.remove(value.getUnitId());
        }

        //删除unitCreativeMap
        Set<Long> creativeSet = unitCreativeMap.get(value.getUnitId());//根据unitId获取与之关联的创意set
        if (CollectionUtils.isNotEmpty(creativeSet)) {
            creativeSet.remove(value.getAdId());
        }

        log.info("after delete: {}", objectMap);
    }


    /**
     * 通过推广单元获取关联的创意实现
     * 创意与推广单元存在着多对多的关系
     * 1、可以通过creativeUnitIndex索引服务以及creativeUnitObject去获取到推广单元所有关联的创意的id
     * 2、再通过creativeIndex通过id再获取到对应的CreativeObject
     *
     * 这里实现第一步
     */
    public List<Long> selectAds(List<AdUnitObject> unitObjects) {

        //非空校验
        if (CollectionUtils.isEmpty(unitObjects)) {
            return Collections.emptyList();
        }

        //返回得到的ids
        List<Long> result = new ArrayList<>();

        for (AdUnitObject unitObject : unitObjects) {

            //通过索引服务的 map 根据 id  获取对应的 object
            Set<Long> adIds = unitCreativeMap.get(unitObject.getUnitId());
            if (CollectionUtils.isNotEmpty(adIds)) {
                result.addAll(adIds);
            }
        }

        return result;
    }
}
